// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#include "coin2/exchange/kraken/api_util/auth_key.h"

#include <algorithm>

#include "coin2/base/base64.h"
#include "coin2/exchange/base/api_util/api_signature.h"
#include "coin2/exchange/base/api_util/json_writer.h"

std::string KrakenBaseAuth::GetSignature(
    const std::string& secret_key,
    const std::string& address,
    const std::string& timestamp,
    const std::string& param) {
  if (secret_key.empty()) {
    throw std::runtime_error("[kraken] secret key is empty");
  }
  std::string data(address);
  auto nonce_postdata = ApiSignatureUtil::GetHashByRawSHA256(timestamp + param);
  data += nonce_postdata;
  auto sha_result =
      ApiSignatureUtil::GetSignatureByHmacSHA512(data, impl::base64_decode(secret_key));
  return sha_result;
}

std::list<std::string> KrakenWsAuth::GetSignatureStringList() const {
  std::list<std::string> out;
  std::string ts_str = "TODO";
  std::string signa = GetSignature(key_.secret_key(), "/users/self/verify", ts_str, "");
  out.emplace_back(key_.access_key());
  out.emplace_back(key_.GetValue("passphrase").value());
  out.emplace_back(ts_str);
  out.emplace_back(signa);
  return out;
}

std::string KrakenWsAuth::CreateSignature() const {
  return R"({"type":"subscribe","channels":[{"name":"heartbeat","product_ids":["BTC-USD"]}]})";
}

std::vector<std::pair<std::string, std::string>> KrakenRestAuth::GetHeaderSet(
    const std::string& address,
    const std::string& timestamp,
    const std::string& param) const {
  std::vector<std::pair<std::string, std::string>> out;
  std::string signa = GetSignature(key_.secret_key(), address, timestamp, param);
  out.push_back(std::make_pair("API-Key", key_.access_key()));
  out.push_back(std::make_pair("API-Sign", signa));
  out.push_back(std::make_pair("Content-Type", "application/x-www-form-urlencoded"));
  return out;
}

AsioHttpContext* KrakenRestAuth::CreateRequestByPostWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string query_string = builder->ComputeQueryString();
  nonce_ = std::max(nonce_ + 1, GetCurrentTimestamp() / 1000000);
  builder->PutPost("nonce", std::to_string(nonce_));
  std::string post_body = builder->ComputePostBodyAsQueryString();
  std::string target = address;
  if (!query_string.empty()) {
    target += "?" + query_string;
  }
  auto ahc = AsioHttpContext::NewPost(
      host_,
      port_,
      bind_ip_,
      target,
      GetHeaderSet(address, std::to_string(nonce_), post_body),
      post_body);
  ahc->keep_user_agent = true;
  return ahc;
}
